﻿using ClassLibrary1;
using DependencyAnalysis.DataModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PrinciplesP = DependencyAnalysis.Principles;

namespace UnitTests.Principles
{
    [TestClass]
    public class LawOfDemeterTest : AnalyzerTestBase
    {
        [TestMethod]
        public void WhenNoViolationsThenReturnEmptyList()
        {
            var lawOfDemeter = PrinciplesP.LawOfDemeter(new DependencyModel());
            Assert.IsNotNull(lawOfDemeter);
        }

        [TestMethod]
        public void WhenConcatenationOfClassesThenReport()
        {
            var memberDescriptor = DescriptorBuilder.BuildMemberDescriptor(typeof(LawOfDemeterClass).GetMethod("ConcatenationOfClasses"));
            var violations = PrinciplesP.LawOfDemeter(Model);
            
            Assert.IsTrue(violations.ContainsKey(memberDescriptor));
        }

        [TestMethod]
        public void WhenAccessingCurrentClassThenIgnore()
        {
            var memberDescriptor = DescriptorBuilder.BuildMemberDescriptor(typeof(LawOfDemeterClass).GetMethod("ConcatenateCallsToSelf"));
            var violations = PrinciplesP.LawOfDemeter(Model);

            Assert.IsFalse(violations.ContainsKey(memberDescriptor));
        }

        [TestMethod]
        public void WhenSequenceIsFilledWithCastsThenIgnoreCasts()
        {
            var memberDescriptor = DescriptorBuilder.BuildMemberDescriptor(typeof(LawOfDemeterClass).GetMethod("CastInstructions"));
            var violations = PrinciplesP.LawOfDemeter(Model);

            Assert.IsTrue(violations.ContainsKey(memberDescriptor));
        }

        [TestMethod]
        public void WhenCallToForeignFieldThenReport()
        {
            var memberDescriptor = DescriptorBuilder.BuildMemberDescriptor(typeof(LawOfDemeterClass).GetMethod("CallToField"));
            var violations = PrinciplesP.LawOfDemeter(Model);

            Assert.IsTrue(violations.ContainsKey(memberDescriptor));
        }
        
        [TestMethod]
        public void WhenObjectIsPassedAsParameterThenIgnoreThatCall()
        {
            var memberDescriptor = DescriptorBuilder.BuildMemberDescriptor(typeof(LawOfDemeterClass).GetMethod("PassingAsParameter"));
            var violations = PrinciplesP.LawOfDemeter(Model);

            Assert.IsFalse(violations.ContainsKey(memberDescriptor));
        }

        [TestMethod]
        public void WhenCallToCommonTypesMemberThenIgnoreThatCall()
        {
            var memberDescriptor = DescriptorBuilder.BuildMemberDescriptor(typeof(LawOfDemeterClass).GetMethod("MembersOfCommonTypes"));
            var violations = PrinciplesP.LawOfDemeter(Model);

            Assert.IsFalse(violations.ContainsKey(memberDescriptor));
        }

        [TestMethod]
        public void WhenCallResultIsPassedAsParameterThenIgnore()
        {
            var memberDescriptor = DescriptorBuilder.BuildMemberDescriptor(typeof(LawOfDemeterClass).GetMethod("PassingCallAsParameter"));
            var violations = PrinciplesP.LawOfDemeter(Model);

            Assert.IsFalse(violations.ContainsKey(memberDescriptor));
        }

        [TestMethod]
        public void WhenCallingMultipleMethodsThenIgnore()
        {
            var memberDescriptor = DescriptorBuilder.BuildMemberDescriptor(typeof(LawOfDemeterClass).GetMethod("ConsecutiveCalls"));
            var violations = PrinciplesP.LawOfDemeter(Model);

            Assert.IsFalse(violations.ContainsKey(memberDescriptor));
        }

        [TestMethod]
        public void WhenCallingDataObjectsThenIgnore()
        {
            var memberDescriptor = DescriptorBuilder.BuildMemberDescriptor(typeof(LawOfDemeterClass).GetMethod("CallDataObjects"));
            var violations = PrinciplesP.LawOfDemeter(Model);

            Assert.IsFalse(violations.ContainsKey(memberDescriptor));
        }

        [TestMethod]
        public void WhenCompilerGeneratedThenIgnore()
        {
            var memberDescriptor = DescriptorBuilder.BuildMemberDescriptor(typeof(LawOfDemeterClass).GetMethod("GeneratedCode"));
            var violations = PrinciplesP.LawOfDemeter(Model);

            Assert.IsFalse(violations.ContainsKey(memberDescriptor));
        }

        [TestMethod]
        public void WhenCalledDataObjectIsReturnedBeforeThenReport()
        {
            var memberDescriptor = DescriptorBuilder.BuildMemberDescriptor(typeof(LawOfDemeterClass).GetMethod("CallClassThenDataObjects"));
            var violations = PrinciplesP.LawOfDemeter(Model);

            Assert.IsTrue(violations.ContainsKey(memberDescriptor));
        }

        [TestMethod]
        public void WhenCallsHaveOherParametersThenReport()
        {
            var memberDescriptor = DescriptorBuilder.BuildMemberDescriptor(typeof(LawOfDemeterClass).GetMethod("ConcatenationWithParameters"));
            var violations = PrinciplesP.LawOfDemeter(Model);

            Assert.IsTrue(violations.ContainsKey(memberDescriptor));
        }

        [Ignore]
        [TestMethod]
        public void WhenBuilderPatternTheAllow()
        {
        }
    }
}
